/*
 * This file is part of JSTUN. 
 * 
 * Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
 * reserved.
 * 
 * This software is licensed under either the GNU Public License (GPL),
 * or the Apache 2.0 license. Copies of both license agreements are
 * included in this distribution.
 */

package de.javawi.jstun.attribute;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.javawi.jstun.util.Utility;
import de.javawi.jstun.util.UtilityException;

@SuppressWarnings("PMD")
public abstract class MessageAttribute implements MessageAttributeInterface {
	private static final Logger LOGGER = LoggerFactory.getLogger(MessageAttribute.class);
	MessageAttributeType type;

	public MessageAttribute() {
	}

	public MessageAttribute(final MessageAttributeType type) {
		setType(type);
	}

	public void setType(final MessageAttributeType type) {
		this.type = type;
	}

	public MessageAttribute.MessageAttributeType getType() {
		return type;
	}

	public static int typeToInteger(final MessageAttributeType type) {
		if (type == MessageAttributeType.MappedAddress) {
			return MAPPEDADDRESS;
		}
		if (type == MessageAttributeType.ResponseAddress) {
			return RESPONSEADDRESS;
		}
		if (type == MessageAttributeType.ChangeRequest) {
			return CHANGEREQUEST;
		}
		if (type == MessageAttributeType.SourceAddress) {
			return SOURCEADDRESS;
		}
		if (type == MessageAttributeType.ChangedAddress) {
			return CHANGEDADDRESS;
		}
		if (type == MessageAttributeType.Username) {
			return USERNAME;
		}
		if (type == MessageAttributeType.Password) {
			return PASSWORD;
		}
		if (type == MessageAttributeType.MessageIntegrity) {
			return MESSAGEINTEGRITY;
		}
		if (type == MessageAttributeType.ErrorCode) {
			return ERRORCODE;
		}
		if (type == MessageAttributeType.UnknownAttribute) {
			return UNKNOWNATTRIBUTE;
		}
		if (type == MessageAttributeType.ReflectedFrom) {
			return REFLECTEDFROM;
		}
		if (type == MessageAttributeType.Dummy) {
			return DUMMY;
		}
		return -1;
	}

	public static MessageAttributeType intToType(final long type) {
		if (type == MAPPEDADDRESS) {
			return MessageAttributeType.MappedAddress;
		}
		if (type == RESPONSEADDRESS) {
			return MessageAttributeType.ResponseAddress;
		}
		if (type == CHANGEREQUEST) {
			return MessageAttributeType.ChangeRequest;
		}
		if (type == SOURCEADDRESS) {
			return MessageAttributeType.SourceAddress;
		}
		if (type == CHANGEDADDRESS) {
			return MessageAttributeType.ChangedAddress;
		}
		if (type == USERNAME) {
			return MessageAttributeType.Username;
		}
		if (type == PASSWORD) {
			return MessageAttributeType.Password;
		}
		if (type == MESSAGEINTEGRITY) {
			return MessageAttributeType.MessageIntegrity;
		}
		if (type == ERRORCODE) {
			return MessageAttributeType.ErrorCode;
		}
		if (type == UNKNOWNATTRIBUTE) {
			return MessageAttributeType.UnknownAttribute;
		}
		if (type == REFLECTEDFROM) {
			return MessageAttributeType.ReflectedFrom;
		}
		if (type == DUMMY) {
			return MessageAttributeType.Dummy;
		}
		return null;
	}

	abstract public byte[] getBytes() throws UtilityException;

	// abstract public MessageAttribute parse(byte[] data) throws MessageAttributeParsingException;

	public int getLength() throws UtilityException {
		final int length = getBytes().length;
		return length;
	}

	public static MessageAttribute parseCommonHeader(final byte[] data) throws MessageAttributeParsingException {
		try {
			final byte[] typeArray = new byte[2];
			System.arraycopy(data, 0, typeArray, 0, 2);
			final int type = Utility.twoBytesToInteger(typeArray);
			final byte[] lengthArray = new byte[2];
			System.arraycopy(data, 2, lengthArray, 0, 2);
			final int lengthValue = Utility.twoBytesToInteger(lengthArray);
			final byte[] valueArray = new byte[lengthValue];
			System.arraycopy(data, 4, valueArray, 0, lengthValue);
			MessageAttribute ma;
			switch (type) {
				case MAPPEDADDRESS:
					ma = MappedAddress.parse(valueArray);
					break;
				case RESPONSEADDRESS:
					ma = ResponseAddress.parse(valueArray);
					break;
				case CHANGEREQUEST:
					ma = ChangeRequest.parse(valueArray);
					break;
				case SOURCEADDRESS:
					ma = SourceAddress.parse(valueArray);
					break;
				case CHANGEDADDRESS:
					ma = ChangedAddress.parse(valueArray);
					break;
				case USERNAME:
					ma = Username.parse(valueArray);
					break;
				case PASSWORD:
					ma = Password.parse(valueArray);
					break;
				case MESSAGEINTEGRITY:
					ma = MessageIntegrity.parse(valueArray);
					break;
				case ERRORCODE:
					ma = ErrorCode.parse(valueArray);
					break;
				case UNKNOWNATTRIBUTE:
					ma = UnknownAttribute.parse(valueArray);
					break;
				case REFLECTEDFROM:
					ma = ReflectedFrom.parse(valueArray);
					break;
				default:
					if (type <= 0x7fff) {
						throw new UnknownMessageAttributeException("Unkown mandatory message attribute", intToType(type));
					} else {
						LOGGER.debug("MessageAttribute with type " + type + " unkown.");
						ma = Dummy.parse(valueArray);
						break;
					}
			}
			return ma;
		} catch (final UtilityException ue) {
			throw new MessageAttributeParsingException("Parsing error");
		}
	}
}
